/*
============================================================================
 * decoder_lib.h
 *
 *  Created on: 2011-06-11
 *      Author: Shah Hossain
 ============================================================================
 */

#ifndef DECODER_LIB_H_
#define DECODER_LIB_H_



#endif /* DECODER_LIB_H_ */

char *removeParity(char*,int*);
extern int DEBUG;

char* hamDecode(char *orig_data)
{
	char *data= (char *) malloc(getSize(orig_data)+1);
	strcpy(data,orig_data);
	int receivedParity=0;  //read in received parity
	char *decoded=removeParity(data,&receivedParity);

	char *buffer= shiftParity(decoded);

	int newParity=getParity(buffer);	//recalculate parity
	//free(buffer);

	int error= (newParity ^ receivedParity) - 1; //offsetof 1 when calculating lsb

	if (DEBUG==1) printf("Extracted parity: %#x,  Calculated Parity: %#x\n",receivedParity,newParity);
	if (DEBUG==1) printf("Errorbit: %d\n",error);

	if (DEBUG==1) printf("Received:  ");
	if (DEBUG==1) printStream(decoded,1);

	if (error!=-1)
	{
		changeBIT(data,error,-1);
		decoded=removeParity(data,&receivedParity);
	}
	free (data);

	if (DEBUG==1) printf("Corrected: ");
	if (DEBUG==1) printStream(decoded,1);

	return decoded;

}

//	int extractParity(char*); //read in received parity



char *removeParity(char *data,int *parity)
{
	int sz=getSize(data);
	int space= 0;
	int i;

	unsigned char left_byte=*data;

	int bits_used=sz*8;
	for (i=0; i<8; i++)
	{
		if (left_byte== 0x00)
		{
			bits_used=(sz-1)*8+i;
			break;
		}
		else
			left_byte = left_byte >> 1;
	}
	bits_used = bits_used-(int) log2(bits_used)-1; //bits used for msg
	int bsz= (bits_used-1)/8 + 1;
	if (DEBUG==1) printf("Size: %d\t Bits used: %d\tBuffer size: %d\n",sz,bits_used,bsz);


	int parityPos=1;
	char *buffer=(char*) malloc(bsz+1);
	for (i=0; i<bsz; i++)
		buffer[i]=0x00;
	buffer[bsz]='\0';

	int wr_index=0;
	int rd_index=0;
	int parity_bit=0;
	unsigned char mask= 0x00;

	for(rd_index=0;rd_index<sz*8; rd_index++)
	{
		if (rd_index==(parityPos-1))
		{
			//printf("#%d\t",rd_index);
			parity_bit= data[sz-(rd_index/8)-1] >> rd_index%8;
			parity_bit= parity_bit & 0x01;
			//printf("%#x\t",parity_bit);
			//32 bit parity max
			*parity= (*parity) + (parity_bit  << (int) log2(parityPos));
			parityPos *=2;
		}
		else
		{

			//isolate bit, shift into position, mask in
			mask = data[sz-(rd_index/8)-1] >> rd_index%8;
			mask &= 0x01;
			//printf("%d->%d\t",rd_index,mask);
			mask = mask << wr_index%8;
			if (mask==0) //reset bit
				buffer[bsz-1-(wr_index/8)] &= ~mask;
			else	//set bit
				buffer[bsz-1-(wr_index/8)] |= mask;

			wr_index++;

		}

	}

	space=rd_index-wr_index;
	//pad out remaining bits
	for(; space>0; space--)
	{
		mask = 1 << (wr_index+space)%8;
		buffer[bsz-1-((wr_index+space)/8)] &= ~mask;
	}

	return buffer;
}
